﻿namespace BadHabit.Factory
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    public partial class FactoryLogic
    {
        private static Data.TaskDataSetTableAdapters.TaskTailTableAdapter taskTailAD = new BadHabit.Factory.Data.TaskDataSetTableAdapters.TaskTailTableAdapter();
        private static Data.TaskDataSetTableAdapters.TaskTailImpactedItemTableAdapter taskTailImpactedItemAD = new BadHabit.Factory.Data.TaskDataSetTableAdapters.TaskTailImpactedItemTableAdapter();
        private static Data.TaskDataSetTableAdapters.TaskTableAdapter taskAD = new BadHabit.Factory.Data.TaskDataSetTableAdapters.TaskTableAdapter();

        /// <summary>
        /// Creates a tail between a given team member and a group of artifacts.
        /// It detects what is the task that the team member is current working to tail it.
        /// </summary>
        /// <param name="repositoryURL">The Artifact repository URL</param>
        /// <param name="teamMember">The team member</param>
        /// <param name="artifactsPath">The modified artifacts</param>
        /// <param name="revision">The revision number</param>
        public Data.TaskDataSet TailTaskByTeamMember(string repositoryURL, string teamMember, string[] artifactsPath, int revision)
        {
            string taskUId = GetWorkingTaskUIdByTeamMember(teamMember);
            if (taskUId == null || taskUId.Trim().Equals(Guid.Empty.ToString()))
            {
                throw new Exception("Can´t tail task. " + teamMember + " is not working at any task now.");
            }

            this.TailArtifacts(repositoryURL, taskUId, artifactsPath, revision, true);

            Data.TaskDataSet task = new BadHabit.Factory.Data.TaskDataSet();
            taskAD.FillByTaskUId(task.Task, taskUId);

            return task;
        }

        /// <summary>
        /// Creates a tail between a given task and a group of artifacts.
        /// </summary>
        /// <param name="repositoryURL">The Artifact repository URL</param>
        /// <param name="taskId">The taskId</param>
        /// <param name="artifactsPath">The modified artifacts</param>
        /// <param name="revision">The revision number</param>
        public Data.TaskDataSet TailTaskById(string repositoryURL, int taskId, string[] artifactsPath, int revision)
        {
            Data.TaskDataSet task = new BadHabit.Factory.Data.TaskDataSet();

            string taskUId = null;
            taskAD.FillByTaskId(task.Task, taskId);

            if (task.Task.Rows.Count == 0)
            {
                throw new Exception("Task " + taskId + " was not found.");
            }

            taskUId = task.Task[0].TaskUId;

            this.TailArtifacts(repositoryURL, taskUId, artifactsPath, revision, true);

            return task;
        }

        private void TailArtifacts(string repositoryURL, string taskUId, string[] artifactsPath, int revision, bool isSourceControled)
        {
            Data.TaskDataSet task = new BadHabit.Factory.Data.TaskDataSet();

            foreach (string artifact in artifactsPath)
            {
                string extension = GetArtifactExtension(artifact);

                if (!extension.Equals(string.Empty))
                {
                    taskTailAD.TailTaskByTaskUId(
                    Guid.NewGuid().ToString().ToLower(),
                    taskUId,
                    artifact,
                    revision,
                    extension,
                    DateTime.Now,
                    repositoryURL,
                    isSourceControled);
                }
            }
        }

        public void TailTaskMaterial(string taskUId, string[] materialPath)
        {
            this.TailArtifacts(string.Empty, taskUId, materialPath, 0, false);
        }

        public void DeleteTaskTail(string taskTailUId)
        {
            taskTailAD.DeleteByTaskTailUId(taskTailUId);
        }

        public void DeleteTaskTail(string backlogItemUId, string artifactPath)
        {
            taskTailAD.DeleteByArtifactPathAndBacklogItemUId(artifactPath, backlogItemUId);
        }

        /// <summary>
        /// Gets a artifact file extension.
        /// </summary>
        /// <param name="artifactPath">The artifact path</param>
        /// <returns>The file extension</returns>
        private static string GetArtifactExtension(string artifactPath)
        {
            string artifactName = artifactPath;

            if (artifactPath.Contains('/'))
            {
                artifactName = artifactPath.Substring(artifactPath.LastIndexOf('/'));
            }

            if (artifactName.IndexOf('.') == -1)
            {
                return String.Empty;
            }

            return artifactName.Substring(artifactName.IndexOf('.'));
        }

        private string GetArtifactName(string artifactPath)
        {
            if (artifactPath == null)
            {
                return String.Empty;
            }

            artifactPath = artifactPath.Replace("\\", "/");
            
            int lastIndex = artifactPath.LastIndexOf('/');
            if (lastIndex < 0)
            {
                return String.Empty;
            }

            return artifactPath.Substring(lastIndex + 1);
        }

        public Data.TaskDataSet RetriveArtifactsByTaskUId(string taskUId)
        {
            // first retrives the tailed tasks
            Data.TaskDataSet ds = new BadHabit.Factory.Data.TaskDataSet();
            taskTailAD.FillByTaskUId(ds.TaskTail, taskUId);

            // now tries to find the cycle definition
            Data.CycleDefinitionDataSet cycle = null;
            if (ds.TaskTail.Count > 0)
            {
                try
                {
                    Data.ProjectDataSet project = RetriveProject(ds.TaskTail[0].ProjectUId);
                    if (project.Project.Count > 0)
                    {
                        cycle = this.RetriveCycleDefinition(project.Project[0].Category);
                    }
                }
                catch
                {
                }
            }

            // fills the cycle information
            this.FillCycleInformation(ds.TaskTail, cycle);

            return ds;
        }

        public Data.TaskDataSet RetriveArtifactsByBacklogItemUId(string backlogItemUId, string projectCategory)
        {
            Data.TaskDataSet ds = new BadHabit.Factory.Data.TaskDataSet();
            taskTailAD.FillByBacklogItemUId(ds.TaskTail, backlogItemUId);

            // reads the project cycle information
            Data.CycleDefinitionDataSet cycle = null;
            try
            {
                cycle = this.RetriveCycleDefinition(projectCategory);
            }
            catch
            {
            }

            this.FillCycleInformation(ds.TaskTail, cycle);

            return ds;
        }

        public Data.TaskDataSet RetriveArtifactsByProjectUId(string projectUId, string projectCategory)
        {
            Data.TaskDataSet ds = new BadHabit.Factory.Data.TaskDataSet();
            taskTailAD.FillArtifactsByProjectUId(ds.TaskTail, projectUId);

            // reads the project cycle information
            Data.CycleDefinitionDataSet cycle = null;
            try
            {
                cycle = this.RetriveCycleDefinition(projectCategory);
            }
            catch
            {
            }

            this.FillCycleInformation(ds.TaskTail, cycle);

            return ds;
        }

        public Data.TaskDataSet RetriveTailsByProjectUId(string projectUId, string projectCategory)
        {
            Data.TaskDataSet ds = new BadHabit.Factory.Data.TaskDataSet();
            taskTailAD.FillByProjectUId(ds.TaskTail, projectUId);

            // reads the project cycle information
            Data.CycleDefinitionDataSet cycle = null;
            try
            {
                cycle = this.RetriveCycleDefinition(projectCategory);
            }
            catch
            {
            }

            this.FillCycleInformation(ds.TaskTail, cycle);

            return ds;
        }

        public Data.TaskDataSet RetriveImpactedItemsByProjectUId(string projectUId)
        {
            Data.TaskDataSet ds = new BadHabit.Factory.Data.TaskDataSet();
            taskTailImpactedItemAD.FillByProjectUId(ds.TaskTailImpactedItem, projectUId);

            return ds;
        }

        public Data.TaskDataSet RetriveImpactedItemsByTaskUId(string taskUId)
        {
            Data.TaskDataSet ds = new BadHabit.Factory.Data.TaskDataSet();
            taskTailImpactedItemAD.FillByTaskUId(ds.TaskTailImpactedItem, taskUId);

            return ds;
        }

        public Data.TaskDataSet RetriveImpactedItemsByTailUId(string tailUId)
        {
            Data.TaskDataSet ds = new BadHabit.Factory.Data.TaskDataSet();
            taskTailImpactedItemAD.FillByTailUId(ds.TaskTailImpactedItem, tailUId);

            return ds;
        }

        public Data.TaskDataSet RetriveImpactedItemsByBacklogItemUId(string backlogItemUId)
        {
            Data.TaskDataSet ds = new BadHabit.Factory.Data.TaskDataSet();
            taskTailImpactedItemAD.FillBySourceBacklogItemUId(ds.TaskTailImpactedItem, backlogItemUId);

            return ds;
        }

        public Data.TaskDataSet RetriveTasksByTailedBacklogItemUId(string backlogItemUId)
        {
            Data.TaskDataSet task = new BadHabit.Factory.Data.TaskDataSet();
            taskResumeTA.FillByTailedBacklogItemUId(task.TaskResume, backlogItemUId);

            return task;
        }

        public Data.TaskDataSet RetriveTasksByTailedProjectUId(string projectUId)
        {
            Data.TaskDataSet task = new BadHabit.Factory.Data.TaskDataSet();
            taskResumeTA.FillByTailedProjectUId(task.TaskResume, projectUId);

            return task;
        }

        public Data.TaskDataSet RetriveTasksByTailUId(string tailUId)
        {
            Data.TaskDataSet task = new BadHabit.Factory.Data.TaskDataSet();
            taskResumeTA.FillByTailUId(task.TaskResume, tailUId);

            return task;
        }

        public Data.TaskDataSet RetriveTasksByArtifactPath(string artifactPath)
        {
            Data.TaskDataSet task = new BadHabit.Factory.Data.TaskDataSet();
            taskResumeTA.FillByArtifactPath(task.TaskResume, artifactPath);

            return task;
        }

        public Data.CycleDefinitionDataSet RetriveCycleDefinition(string projectCategory)
        {
            // read the project from the XML template file
            Data.CycleDefinitionDataSet cycle = new Data.CycleDefinitionDataSet();
            string path = ServerPath + @"\App_Data\ProjectTemplates\" + projectCategory + @"\CycleDefinition.xml";
            cycle.ReadXml(path);

            return cycle;
        }

        /// <summary>
        /// Fills the cycle infomration at the task tail table.
        /// </summary>
        /// <param name="tailTable">The taskTail Table</param>
        /// <param name="cycleDefinition">The cycle definition</param>
        public void FillCycleInformation(Data.TaskDataSet.TaskTailDataTable tailTable, Data.CycleDefinitionDataSet cycleDefinition)
        {
            // now for every, artifact, fill its value
            foreach (Data.TaskDataSet.TaskTailRow tail in tailTable)
            {
                tail.ArtifactName = this.GetArtifactName(tail.ArtifactPath);
                tail.ArtifactGroup = "Unknow Artifacts";
                tail.ActivityName = "Unknow Sprint Activity";
                tail.ActivityOrder = 1000;

                if (cycleDefinition != null)
                {
                    Data.CycleDefinitionDataSet.ArtifactRow artifactDef = this.FindArtifactDefinitionForTail(tail, cycleDefinition);
                    if (artifactDef != null)
                    {
                        tail.ActivityName = artifactDef.ActivityName;
                        tail.ActivityOrder = artifactDef.SprintFaseRow.ActivityOrder;
                        tail.ArtifactGroup = artifactDef.ArtifactGroup;

                        if (!artifactDef.IsTypeNull())
                        {
                            tail.ArtifactGroupType = artifactDef.Type;
                        }
                    }
                }
            }
        }

        private Data.CycleDefinitionDataSet.ArtifactRow FindArtifactDefinitionForTail(Data.TaskDataSet.TaskTailRow tail, Data.CycleDefinitionDataSet cycleDefinition)
        {
            // verifies all artifacts definition to see what one is it
            foreach (Data.CycleDefinitionDataSet.ArtifactRow artifactDef in cycleDefinition.Artifact)
            {
                // first check the startwidth rule
                if (!artifactDef.IsStartsWithRuleNull() && tail["ArtifactName"].ToString().StartsWith(artifactDef.StartsWithRule))
                {
                    return artifactDef;
                }

                // then check the extension rules
                if (!artifactDef.IsExtentionRuleNull() && this.IsAtExtensionRule(tail.ArtifactExtension, artifactDef.ExtentionRule))
                {
                    return artifactDef;
                }
            }

            return null;
        }

        private bool IsAtExtensionRule(string ext, string rule)
        {
            string[] extArray = rule.Split(' ');
            for (int i = 0; i < extArray.Length; i++)
            {
                if (ext.ToLower().Equals(extArray[i].ToLower()))
                {
                    return true;
                }
            }

            return false;
        }
    }
}